﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Web.UI;
using PlanificadorDeEventos.Models;
using PlanificadorDeEventos.Repositorios;
using PlanificadorDeEventos.Comun;
using PlanificadorDeEventos.Interfaces;
using MvcFilters.Filters;

namespace Eventos.Controllers
{
    [HandleError]
    public class EventoController : Controller
    {

        #region Miembros privados
        private IRepositorioEventos repoEventos;
        private IRepositorioEventoUsuarioOrganizados repoEventosOrganizados;
        private IRepositorioEventoUsuarioRegistrados repoEventosRegistrados;
        private IRepositorioGuests repoGuests;
        string pathPageError = "../Shared/Error";
        #endregion
            
        #region Constructor
        public EventoController(IRepositorioEventos RepositorioEventos, IRepositorioEventoUsuarioOrganizados RepositorioEventoUsuarioOrganizados, IRepositorioEventoUsuarioRegistrados RepositorioEventoUsuarioRegistrados, IRepositorioGuests RepositorioGuests)
        {
            repoEventos = RepositorioEventos;
            repoEventosOrganizados = RepositorioEventoUsuarioOrganizados;
            repoEventosRegistrados = RepositorioEventoUsuarioRegistrados;
            repoGuests = RepositorioGuests;
        }
    
        #endregion

        #region Métodos públicos
        [OutputCache(Duration = 10, VaryByParam = "none", Location = OutputCacheLocation.Any)]
        [TraceFilter]
        [LogErrors]
        public ActionResult Index()
        {
            return View(this.repoEventos.Get(e => e.Date > DateTime.Now));
        }

        //
        // GET: /Evento/Details/5
        [TraceFilter]
        [LogErrors]
        public ActionResult Details(int id = 0)
        {
            Evento evento = repoEventos.GetByID(id);
            if (evento == null)
                return View(pathPageError);
            ViewBag.id = id;
            ViewBag.Participantes = repoEventosRegistrados.ObtenerPorIdEvento(id);
            String usuario = System.Web.HttpContext.Current.User.Identity.Name;
            IEnumerable<EventoUsuarioOrganizado> list = null;
            ViewBag.showconfirm = repoEventosOrganizados.ObtenerPorNombreUsuario(usuario).Where(ev => ev.EventoID.Equals(id)).Count() > 0;//si el usuario logueado es organizador del evento
            list = repoEventosOrganizados.ObtenerPorIdEvento(id);
            ViewBag.Organizadores = list.ToList();
            return View(evento);
        }

        //
        // GET: /Evento/Create
        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult Create()
        {
            return View();
        }

        //
        // POST: /Evento/Create
        [Authorize(Roles = "Usuario")]
        [HttpPost]
        [TraceFilter]
        [LogErrors]
        public ActionResult Create(Evento evento)
        {
            if (ModelState.IsValid)
            {
                User u = (User)repoGuests.ObtenerPorNombre(System.Web.HttpContext.Current.User.Identity.Name);
                if (u == null)
                    return View(pathPageError);
                repoEventos.Insert(evento);
                EventoUsuarioOrganizado euo = new EventoUsuarioOrganizado();
                euo.GuestID = u.ID;
                euo.EventoID = evento.ID;
                repoEventosOrganizados.Insert(euo);
                return RedirectToAction("Index");
            }
            return View(evento);
        }

        //
        // GET: /Evento/Edit/5
        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult Edit(int id = 0)
        {
            if (Roles.GetRolesForUser(System.Web.HttpContext.Current.User.Identity.Name).Contains("Admin"))
                ViewBag.isAdmin = true;
            else
                ViewBag.isAdmin = false;

            Evento evento = repoEventos.GetByID(id);
            if (evento == null)
            {
                return HttpNotFound();
            }
            return View(evento);
        }

        //
        // POST: /Evento/Edit/5

        [HttpPost]
        [Authorize]
        [TraceFilter]
        [LogErrors]
        public ActionResult Edit(Evento evento)
        {
            if (ModelState.IsValid)
            {
                repoEventos.ActualizarEvento(evento);
                return RedirectToAction("Index");
            }
            return View(evento);
        }

        //
        // GET: /Evento/Delete/5
        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult Delete(int id = 0)
        {
            Evento evento = repoEventos.GetByID(id);
            if (evento == null)
                return View(pathPageError);
            ViewBag.nombreAccion = "¿Desea eliminar el evento?";
            ViewBag.accionConfirmar = "DeleteConfirmed";
            ViewBag.idAEliminar = id;
            return PartialView("../Shared/popUpConfirmacion");
        }


        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult DeleteConfirmed(int id)
        {
            Evento evento = repoEventos.GetByID(id);
            if (evento == null)
                return View(pathPageError);
            repoEventos.Delete(evento);
            return PartialView("Close");
        }


        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        /// <summary>
        /// Busca los eventos por su nombre
        /// </summary>
        [TraceFilter]
        [LogErrors]
        public ActionResult Filtrar(string name)
        {
            return this.filter(name, "Index");
        }

        /// <summary>
        /// Busca los eventos propios por su nombre
        /// </summary>
        [Authorize]
        [TraceFilter]
        [LogErrors]
        public ActionResult FiltrarMisEventos(string name)
        {
            return this.filter(name, "MisEventos");
        }

        /// <summary>
        /// Filtra los eventos por su nombre
        /// </summary>
        [TraceFilter]
        [LogErrors]
        private ActionResult filter(string name, String src)
        {
            String UserLogin = System.Web.HttpContext.Current.User.Identity.Name;
            if (string.IsNullOrEmpty(name))
            {
                if (src.Equals("Index"))
                    return View(src, repoEventos.Get(e => e.Date > DateTime.Now));
                else
                    return View(src, (from euo in repoEventosOrganizados.ObtenerPorNombreUsuario(UserLogin) select euo.Evento).ToList());
            }
            else
            {
                ViewBag.Name = name;
                if (src.Equals("Index"))
                    return View(src, repoEventos.Get(e => e.Nombre.Contains(name) && e.Date > DateTime.Now));
                else
                    return View(src, (from euo in repoEventosOrganizados.ObtenerPorNombreUsuario(UserLogin) where euo.Evento.Nombre.Contains(name) select euo.Evento).ToList());
            }

        }

        /// <summary>
        /// Registra un usuario a un evento, si el usuario es externo se redirecciona a otra pantalla para ingresar sus datos
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        [TraceFilter]
        [LogErrors]
        public ActionResult Register(int id)
        {
            String user = System.Web.HttpContext.Current.User.Identity.Name;
            if (user.Equals(""))
            {
                ViewBag.idEvento = id;
                return View();
            }
            else
            {
                this.RegistrarUsuarioAEvento(repoGuests.ObtenerPorNombre(user), id);
                return RedirectToAction("Details/" + id);
            }

        }

        /// <summary>
        /// Realiza la registración de un usuario a un evento
        /// </summary>
        [TraceFilter]
        [LogErrors]
        public ActionResult Register(Guest g, int id)
        {
            ViewBag.idEvento = id;
            if (ModelState.IsValid)
            {
                int res = this.RegistrarUsuarioAEvento(g, id);
                if (res != 0)   //Si es 0 se registro exitosamente
                {
                    ViewBag.idEvento = id;
                    if (res == 1)
                    {
                        ViewBag.message = "El nombre de usuario ya esta siendo utilizado";
                    }
                    else
                    {
                        ViewBag.message = "Se alcanzo el cupo maximo de participantes al evento";
                    }
                    return View();
                }
            }
            else
            {
                return View();
            }
            return RedirectToAction("Details/" + id);
        }

       // [Authorize(Roles = "Usuario")]
        private int RegistrarUsuarioAEvento(Guest g, int id)
        {
            Evento evento = repoEventos.GetByID(id);
            if ((evento.CupoMaximo == 0 || repoEventosRegistrados.ObtenerPorIdEvento(id).Count() < evento.CupoMaximo))  //si evento.CupoMaximo==0 entonces el cupo es ilimitado 
            {
                if (repoEventosRegistrados.Get(eu => eu.Guest.Nombre.Equals(g.Nombre)).Intersect(repoEventosRegistrados.ObtenerPorIdEvento(id)).Count() == 0)//si no esta registrado al evento
                {
                    EventoUsuarioRegistrado eu = new EventoUsuarioRegistrado();
                    Guest guest = repoGuests.ObtenerPorNombre(g.Nombre);
                    if (guest == null)
                    {
                        repoGuests.Insert(g);
                        eu.GuestID = g.ID;
                    }
                    else
                    {
                        if (!guest.Email.Equals(g.Email))
                            return 1;
                        //guest.Nombre = g.Nombre;
                        //repoGuests.Update(guest);
                        eu.GuestID = guest.ID;
                    }
                    eu.EventoID = evento.ID;
                    eu.confirmado = false;
                    repoEventosRegistrados.Insert(eu);
                    return 0;   //se registro correctamente
                }
                else
                {
                    return 1;   //el usuario ya estaba registrado
                }
            }
            else
            {
                return 2;   //se alcanzo el cupo maximo
            }

        }

        /// <summary>
        /// Retorna a la vista con todos los eventos organizados por el usuario logueado
        /// </summary>
        /// <returns></returns>
        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult MisEventos()
        {
            String UserLogin = System.Web.HttpContext.Current.User.Identity.Name;
            IEnumerable<Evento> eus = (from eventos in repoEventosOrganizados.ObtenerPorNombreUsuario(UserLogin) select eventos.Evento).ToList();
            return View(eus);
        }

        /// <summary>
        /// Confirma la registracion de un usuario a un evento
        /// </summary>
        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult Confirmar(int idEvento, int idGuest)
        {
            EventoUsuarioRegistrado eu = repoEventosRegistrados.ObtenerPorIdUserIdEvento(idGuest, idEvento);
            if (eu == null)
                return View(pathPageError);
            eu.confirmado = true;
            repoEventosRegistrados.Update(eu);
            return RedirectToAction("Details/" + idEvento);
        }

        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult ShowOrganizers(int id = 0)
        {
            String UserLogin = System.Web.HttpContext.Current.User.Identity.Name;
            IEnumerable<Guest> users = (from eventos in repoEventosOrganizados.ObtenerPorIdEvento(id) select eventos.Guest).ToList();
            IEnumerable<Guest> AllUsers = from us in repoGuests.GetAll() where users.Where(u => u.ID.Equals(us.ID)).Count() == 0 && us.GetType() == typeof(User) select us;//todos los usuarios que no son organizadores del evento
            ViewBag.EventId = id;
            ViewBag.ViewType = "add";
            return View(AllUsers.ToList());
        }


        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult AddOrganizer(int UserId = 0, int EventId = 0)
        {
            User u = (User)repoGuests.GetByID(UserId);
            if (u == null)
                return View(pathPageError);
            EventoUsuarioOrganizado euo = new EventoUsuarioOrganizado();
            euo.GuestID = u.ID;
            euo.EventoID = EventId;
            ViewBag.ViewType = "add";
            repoEventosOrganizados.Insert(euo);
            return RedirectToAction("ShowOrganizers/" + EventId);

        }


        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult ShowParticipantes(int id = 0)
        {
            String UserLogin = System.Web.HttpContext.Current.User.Identity.Name;
            IEnumerable<Guest> users = (from eventos in repoEventosRegistrados.ObtenerPorIdEvento(id) select eventos.Guest).ToList();
            if (users.Count() == 0)
                return View(users);
            IEnumerable<Guest> AllUsers = from us in repoGuests.GetAll() where users.Where(u => u.ID.Equals(us.ID)).Count() == 0 && us.GetType() == typeof(User) select us;//todos los usuarios que no son organizadores del evento
            ViewBag.EventId = id;
            ViewBag.ViewType = "add";
            return View(AllUsers.ToList());
        }


        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult AddParticipante(int UserId = 0, int EventId = 0)
        {
            User user = (User)repoGuests.GetByID(UserId);
            if (user == null)
                return View(pathPageError);
            EventoUsuarioRegistrado euo = new EventoUsuarioRegistrado();
            euo.GuestID = user.ID;
            euo.EventoID = EventId;
            euo.confirmado = true;
            ViewBag.ViewType = "add";
            repoEventosRegistrados.Insert(euo);
            return RedirectToAction("ShowParticipantes/" + EventId);
        }


        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult RemoveOrganizers(int id = 0)
        {
            String UserLogin = System.Web.HttpContext.Current.User.Identity.Name;
            IEnumerable<Guest> users = from eventos in repoEventosOrganizados.ObtenerPorIdEvento(id) select eventos.Guest;
            IEnumerable<Guest> AllUsers = from us in repoGuests.GetAll() where users.Where(u => u.ID.Equals(us.ID)).Count() != 0 && (us.GetType() == typeof(User) || us.GetType() == typeof(Administrador)) select us;//todos los usuarios/administradores que no son organizadores del evento
            ViewBag.EventId = id;
            ViewBag.ViewType = "remove";
            return View("ShowOrganizers", AllUsers.ToList());
        }

        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult RemoveOrganizer(int UserId = 0, int EventId = 0)
        {
            EventoUsuarioOrganizado euo = repoEventosOrganizados.ObtenerPorIdUserIdEvento(UserId, EventId);
            if (euo == null)
                return View(pathPageError);
            repoEventosOrganizados.Delete(euo);
            ViewBag.ViewType = "remove";
            return RedirectToAction("RemoveOrganizers/" + EventId);
        }

        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult RemoveParticipantes(int id = 0)
        {
            String UserLogin = System.Web.HttpContext.Current.User.Identity.Name;
            IEnumerable<Guest> users = from eventos in repoEventosRegistrados.ObtenerPorIdEvento(id) select eventos.Guest;
            IEnumerable<Guest> AllUsers = from us in repoGuests.GetAll() where users.Where(u => u.ID.Equals(us.ID)).Count() != 0 select us;//todos los usuarios que no son organizadores del evento
            ViewBag.EventId = id;
            ViewBag.ViewType = "remove";
            return View("ShowParticipantes", AllUsers.ToList());
        }

        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult RemoveParticipante(int UserId = 0, int EventId = 0)
        {
            EventoUsuarioRegistrado euo = repoEventosRegistrados.ObtenerPorIdUserIdEvento(UserId, EventId);
            if (euo == null)
                return View(pathPageError);
            repoEventosRegistrados.Delete(euo);
            ViewBag.ViewType = "remove";
            return RedirectToAction("RemoveParticipantes/" + EventId);
        }

        /// <summary>
        /// Elimina la registracion de un usuario a un evento
        /// </summary>
        [Authorize(Roles = "Usuario")]
        [TraceFilter]
        [LogErrors]
        public ActionResult Eliminar(int idEvento, int idGuest)
        {
            EventoUsuarioRegistrado eu = repoEventosRegistrados.ObtenerPorIdUserIdEvento(idGuest, idEvento);
            if (eu == null)
                return View(pathPageError);
            repoEventosRegistrados.Delete(eu);
            return RedirectToAction("Details/" + idEvento);
        }

        [Authorize(Roles = "Admin")]
        [TraceFilter]
        [LogErrors]
        public ActionResult VistaAdministrador()
        {
            IEnumerable<Guest> users = from us in repoGuests.GetAll() where (us.GetType() == typeof(User)) select us;
            ViewBag.Eventos = repoEventos.GetAll();
            return View(users.ToList());
        }

        [Authorize(Roles = "Admin")]
        [TraceFilter]
        [LogErrors]
        public ActionResult EliminarUsuarioConfirmed(int id)
        {
            User user = (User)repoGuests.GetByID(id);
            if (user == null)
                return View(pathPageError);
            IEnumerable<EventoUsuarioRegistrado> eur = repoEventosRegistrados.ObtenerPorIdUser(id);
            repoEventosRegistrados.DeleteAll(eur.ToList());
            IEnumerable<EventoUsuarioOrganizado> euo = repoEventosOrganizados.ObtenerPorIdUser(id);

            foreach (var eventoOrganizado in euo.ToList())
            {
                if (repoEventosOrganizados.CantidadDeOrganizadoresPorIdEvento(eventoOrganizado.EventoID).Equals(1)) //el usuario a eliminar es el unico organizador del evento
                {
                    List<EventoUsuarioRegistrado> allRegistraciones = repoEventosRegistrados.ObtenerPorIdEvento(eventoOrganizado.EventoID).ToList();
                    repoEventosRegistrados.DeleteAll(allRegistraciones);
                    repoEventos.Delete(eventoOrganizado.EventoID);
                }
            }
            repoEventosOrganizados.DeleteAll(euo.ToList());
            repoGuests.Delete(id);
            //return RedirectToAction("VistaAdministrador");
            return PartialView("Close");
        }


        [Authorize(Roles = "Admin")]
        [TraceFilter]
        [LogErrors]
        public ActionResult EliminarUsuario(int idUser)
        {
            User user = (User)repoGuests.GetByID(idUser);
            if (user == null)
                return View(pathPageError);

            ViewBag.nombreAccion = "¿Desea eliminar la cuenta de usuario?";
            ViewBag.accionConfirmar = "EliminarUsuarioConfirmed";
            ViewBag.idAEliminar = idUser;
            return PartialView("../Shared/popUpConfirmacion");
        }
        #endregion

    }
}